﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;

using System.Web;

using Awesomium.Core;
using Awesomium.Windows.Controls;
using System.Net;
using System.IO;
using System.Xml;

namespace KinectControls
{
    /// <summary>
    /// Interaction logic for Menu.xaml
    /// </summary>
    public partial class Menu : UserControl
    {
        #region instance variables
        Dictionary<String, List<HoverButton>> menuMap;
        HandCursor leftHand;
        HandCursor rightHand;
        String currentMenu;
        WebControl mapView;
        Slider zoomSlider;
        int resultsIndex;
        int previousAmountOfButtons;
        private List<String> enabledPOIs = new List<String>();

        #endregion

        #region constructor
        public Menu()
        {
            InitializeComponent();
            menuMap = new Dictionary<string, List<HoverButton>>();
            currentMenu = "homeMenu";
            resultsIndex = 0;
            previousAmountOfButtons = 0;
        }

        #endregion

        #region injection methods

        public void injectHands(HandCursor lHand, HandCursor rHand)
        {
            leftHand = lHand;
            rightHand = rHand;
        }

        public void injectMapView(WebControl map)
        {

            mapView = map;
        }

        public void injectZoomSlider(Slider slider)
        {
            zoomSlider = slider;
        }

        #endregion

        public void buildMenu()
        {
            Dictionary<String, List<HoverButton>> menu = new Dictionary<string, List<HoverButton>>();

            // Build home menu
            List<HoverButton> homeMenu = new List<HoverButton>();
            homeMenu.Add(foodButton);
            homeMenu.Add(parkingButton);
            homeMenu.Add(buildingsButton);
            homeMenu.Add(poiButton);
            menu.Add("homeMenu", homeMenu);

            // Build buidling sub menu
            List<HoverButton> buildingsSubMenu = new List<HoverButton>();
            buildingsSubMenu.Add(academicBuildingsButton);
            buildingsSubMenu.Add(residentialBuildingsButton);
            menu.Add("buildingsSubMenu", buildingsSubMenu);

            // Build parking sub menu
            List<HoverButton> parkingSubMenu = new List<HoverButton>();
            parkingSubMenu.Add(academicParkingButton);
            parkingSubMenu.Add(residentialParkingButton);
            parkingSubMenu.Add(visitorParkingButton);
            menu.Add("parkingSubMenu", parkingSubMenu);

            // Build points of interest sub menu
            List<HoverButton> poiSubMenu = new List<HoverButton>();
            poiSubMenu.Add(mensBathroomPoiButton);
            poiSubMenu.Add(womensBathroomPoiButton);
            poiSubMenu.Add(atmPoiButton);
            poiSubMenu.Add(busStopsPoiButton);
            poiSubMenu.Add(bikeRacksPoiButton);
            menu.Add("poiSubMenu", poiSubMenu);

            // Build food results sub menu
            List<HoverButton> foodResults = buildResultMenu("foodResults"); ;
            menu.Add("foodResults", foodResults);

            // Build academic building results sub menu
            List<HoverButton> academicBuildingsResults = buildResultMenu("academicBuildingsResults");
            menu.Add("academicBuildingsResults", academicBuildingsResults);

            // Build residential building results
            List<HoverButton> residentialBuildingsResults = buildResultMenu("residentialBuildingsResults");
            menu.Add("residentialBuildingsResults", residentialBuildingsResults);

            // Build academic parking results
            List<HoverButton> academicParkingResults = buildResultMenu("academicParkingResults");
            menu.Add("academicParkingResults", academicParkingResults);

            // Build residential parking results
            List<HoverButton> residentialParkingResults = buildResultMenu("residentialParkingResults");
            menu.Add("residentialParkingResults", residentialParkingResults);

            // Build visitor parking results
            List<HoverButton> visitorParkingResults = buildResultMenu("visitorParkingResults");
            menu.Add("visitorParkingResults", visitorParkingResults);

            menuMap = menu;
        }

        #region hover button checks
        // Check the appropriate hover buttons depending on what sub menu the menu is on
        public void Check_Hover_Buttons(KinectControls.HandCursor hand)
        {
            switch (currentMenu)
            {
                case "homeMenu":
                    Check_Home_Menu(hand);
                    break;
                case "buildingsSubMenu":
                    Check_Buildings_Menu(hand);
                    break;
                case "parkingSubMenu":
                    Check_Parking_Menu(hand);
                    break;
                case "poiSubMenu":
                    Check_POI_Menu(hand);
                    break;
                default:
                    break;
            }

            if(currentMenu.Contains("Result"))
            {
                Check_Results_Menu(hand);
            }

            if (backButton.Visibility == Visibility.Visible)
            {
                backButton.Check(hand);
            }

            if (clearAllButton.Visibility == Visibility.Visible)
            {
                clearAllButton.Check(hand);
            }
        }

        private void Check_Home_Menu(KinectControls.HandCursor hand)
        {
            foodButton.Check(hand);
            parkingButton.Check(hand);
            buildingsButton.Check(hand);
            poiButton.Check(hand);
        }

        private void Check_Buildings_Menu(KinectControls.HandCursor hand)
        {
            academicBuildingsButton.Check(hand);
            residentialBuildingsButton.Check(hand);
        }

        private void Check_POI_Menu(KinectControls.HandCursor hand)
        {
            mensBathroomPoiButton.Check(hand);
            womensBathroomPoiButton.Check(hand);
            atmPoiButton.Check(hand);
            busStopsPoiButton.Check(hand);
            bikeRacksPoiButton.Check(hand);
        }

        private void Check_Parking_Menu(KinectControls.HandCursor hand)
        {
            academicParkingButton.Check(hand);
            residentialParkingButton.Check(hand);
            visitorParkingButton.Check(hand);
        }

        private void Check_Results_Menu(KinectControls.HandCursor hand)
        {
            scrollUpButton.Check(hand);
            scrollDownButton.Check(hand);

            List<HoverButton> menuButtonList = menuMap[currentMenu];

            foreach (var button in menuButtonList)
            {
                button.Check(hand);
            }
        }

        #endregion

        #region hoverButton Clicks

        public void homeClicked()
        {
            if (currentMenu == "homeMenu")
            {
                mapView.ExecuteJavascript("map.panTo(o_initial_location);");
                mapView.ExecuteJavascript("map.setZoom( 16 );");
                zoomSlider.Value = 3;
            }

            collapseMenu(currentMenu);

            currentMenu = "homeMenu";

            backButton.Visibility = Visibility.Collapsed;

            scrollUpButton.Visibility = Visibility.Collapsed;
            scrollDownButton.Visibility = Visibility.Collapsed;

            resultsIndex = 0;
            previousAmountOfButtons = 0;

            showMenu(currentMenu);
        }

        private void foodButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "foodResults";

            backButton.Visibility = Visibility.Visible;

            clearAllButton.Visibility = Visibility.Visible;

            showMenu(currentMenu);

            showPresets("o1", "Food");
        }

        private void parkingButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "parkingSubMenu";

            showMenu(currentMenu);

            backButton.Visibility = Visibility.Visible;

        }

        private void buildingsButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "buildingsSubMenu";

            showMenu(currentMenu);

            backButton.Visibility = Visibility.Visible;
        }

        private void poiButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "poiSubMenu";

            showMenu(currentMenu);

            backButton.Visibility = Visibility.Visible;
        }

        private void backButton_Click(object sender, EventArgs e)
        {
            scrollUpButton.Visibility = Visibility.Collapsed;
            scrollDownButton.Visibility = Visibility.Collapsed;

            resultsIndex = 0;
            previousAmountOfButtons = 0;

            collapseMenu(currentMenu);

            switch (currentMenu)
            {
                case "homeMenu":
                    break;
                case "buildingsSubMenu":
                    currentMenu = "homeMenu";
                    break;
                case "parkingSubMenu":
                    currentMenu = "homeMenu";
                    break;
                case "poiSubMenu":
                    currentMenu = "homeMenu";
                    break;
                case "foodResults":
                    currentMenu = "homeMenu";
                    break;
                case "academicBuildingsResults":
                    currentMenu = "buildingsSubMenu";
                    break;
                case "residentialBuildingsResults":
                    currentMenu = "buildingsSubMenu";
                    break;
                case "academicParkingResults":
                    currentMenu = "parkingSubMenu";
                    break;
                case "residentialParkingResults":
                    currentMenu = "parkingSubMenu";
                    break;
                case "visitorParkingResults":
                    currentMenu = "parkingSubMenu";
                    break;
                case "mensBathroomPoiResults":
                    currentMenu = "poiSubMenu";
                    break;
                case "womensBathroomPoiResults":
                    currentMenu = "poiSubMenu";
                    break;
                case "atmsPoiResults":
                    currentMenu = "poiSubMenu";
                    break;
                case "busStopsPoiResults":
                    currentMenu = "poiSubMenu";
                    break;
                case "bikeRacksPoiResults":
                    currentMenu = "poiSubMenu";
                    break;
                default:
                    break;
            }

            showMenu(currentMenu);
        }

        private void clearAllButton_Click(object sender, EventArgs e)
        {
            // Remove presets
            mapView.ExecuteJavascript("deleteOverlays()");
            mapView.ExecuteJavascript("infowindow.close()");

            this.enabledPOIs.Clear();
            foreach (HoverButton hb in this.menuMap["poiSubMenu"])
            {
                hb.borderShown = true;
            }

            // remove group markers (POI's)
            removeGroupMarker("bike_racks_marker");
            removeGroupMarker("womens_restrooms_marker");
            removeGroupMarker("mens_restrooms_marker");
            removeGroupMarker("bus_stops_marker");
            removeGroupMarker("atm_marker");

            clearAllButton.Visibility = Visibility.Collapsed;

            if(currentMenu.Contains("Results"))
            {
                backButton_Click(sender, e);
            }
        }

        private void academicBuildingsButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "academicBuildingsResults";

            backButton.Visibility = Visibility.Visible;

            clearAllButton.Visibility = Visibility.Visible;

            showMenu(currentMenu);

            showPresets("b1", "Academic+Building");
        }

        private void residentialBuildingsButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "residentialBuildingsResults";

            backButton.Visibility = Visibility.Visible;

            clearAllButton.Visibility = Visibility.Visible;

            showMenu(currentMenu);

            showPresets("b2", "Residential+Building");
        }

        private void academicParkingButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "academicParkingResults";

            backButton.Visibility = Visibility.Visible;

            clearAllButton.Visibility = Visibility.Visible;

            showMenu(currentMenu);

            showPresets("p1", "Academic+Parking");
        }

        private void residentialParkingButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "residentialParkingResults";

            backButton.Visibility = Visibility.Visible;

            clearAllButton.Visibility = Visibility.Visible;

            showMenu(currentMenu);

            showPresets("p2", "Residential+Parking");
        }

        private void visitorParkingButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);

            currentMenu = "visitorParkingResults";

            backButton.Visibility = Visibility.Visible;

            clearAllButton.Visibility = Visibility.Visible;

            showMenu(currentMenu);

            showPresets("p3", "Visitor+Parking");
        }


        private void mensBathroomPoiButton_Click(object sender, EventArgs e)
        {
            clearAllButton.Visibility = Visibility.Visible;

            showGroupMarkers("Men's+Restroom", "mens_restrooms_marker");

            mensBathroomPoiButton.highlightButton();
        }

        private void womensBathroomPoiButton_Click(object sender, EventArgs e)
        {
            clearAllButton.Visibility = Visibility.Visible;

            showGroupMarkers("Women's+Restroom", "womens_restrooms_marker");

            womensBathroomPoiButton.highlightButton();
        }

        private void atmPoiButton_Click(object sender, EventArgs e)
        {
            clearAllButton.Visibility = Visibility.Visible;

            showGroupMarkers("ATM", "atm_marker");

            atmPoiButton.highlightButton();
        }

        private void busStopsPoiButton_Click(object sender, EventArgs e)
        {
            clearAllButton.Visibility = Visibility.Visible;

            showGroupMarkers("Bus Stop", "bus_stops_marker");

            busStopsPoiButton.highlightButton();
        }

        private void bikeRacksPoiButton_Click(object sender, EventArgs e)
        {
            clearAllButton.Visibility = Visibility.Visible;

            showGroupMarkers("Bike+Rack", "bike_racks_marker");

            bikeRacksPoiButton.highlightButton();
        }
        #endregion

        #region menu displays

        private void collapseMenu(String menu)
        {
            if (!menuMap.ContainsKey(menu))
            {
                return;
            }

            List<HoverButton> menuButtonList = menuMap[menu];

            foreach (var button in menuButtonList)
            {
                button.Visibility = Visibility.Collapsed;
            }
        }

        private void showMenu(String menu)
        {
            if (menuMap.ContainsKey(menu))
            {
                List<HoverButton> menuButtonList = menuMap[menu];

                if (menu.Contains("Results"))
                {
                    showResultsMenu();
                }
                else
                {
                    foreach (var button in menuButtonList)
                    {
                        button.Visibility = Visibility.Visible;
                    }
                }
            }

            switch (currentMenu)
            {
                case "homeMenu":
                    groupBox.Header = "Search";
                    break;
                case "buildingsSubMenu":
                    groupBox.Header = "Buildings";
                    break;
                case "parkingSubMenu":
                    groupBox.Header = "Parking";
                    break;
                case "poiSubMenu":
                    groupBox.Header = "Points of Interest";
                    break;
                case "foodResults":
                    groupBox.Header = "Food";
                    break;
                case "academicBuildingsResults":
                    groupBox.Header = "Academic Buildings";
                    break;
                case "residentialBuildingsResults":
                    groupBox.Header = "Residential Buildings";
                    break;
                case "academicParkingResults":
                    groupBox.Header = "Academic Parking";
                    break;
                case "residentialParkingResults":
                    groupBox.Header = "Residential Parking";
                    break;
                case "visitorParkingResults":
                    groupBox.Header = "Visitor Parking";
                    break;
                case "mensBathroomPoiResults":
                    groupBox.Header = "Points of Interest";
                    break;
                case "womensBathroomPoiResults":
                    groupBox.Header = "Points of Interest";
                    break;
                case "atmsPoiResults":
                    groupBox.Header = "Points of Interest";
                    break;
                case "busStopsPoiResults":
                    groupBox.Header = "Points of Interest";
                    break;
                case "bikeRacksPoiResults":
                    groupBox.Header = "Points of Interest";
                    break;
                default:
                    break;
            }

            if (menu == "homeMenu")
            {
                backButton.Visibility = Visibility.Collapsed;
            }
        }

        private void showResultsMenu(bool up = false)
        {
            List<HoverButton> menuButtonList = menuMap[currentMenu];

            double buttonSpace = menuButtonPanel.ActualHeight - 120;

            int amountOfButtons = (int)(Math.Floor(buttonSpace / 60));

            amountOfButtons -= 2;

            scrollUpButton.Visibility = Visibility.Visible;
            scrollDownButton.Visibility = Visibility.Visible;

            int buttonCounter = 0;

            if (!up)
            {
                if( resultsIndex + (amountOfButtons + 1) >= menuButtonList.Count )
                {
                    scrollDownButton.Visibility = Visibility.Collapsed;
                    amountOfButtons++;
                }

                if(resultsIndex == 0)
                {
                    scrollUpButton.Visibility = Visibility.Collapsed;
                    amountOfButtons++;
                }

                for (int i = resultsIndex; i < menuButtonList.Count; i++)
                {
                    if (buttonCounter >= amountOfButtons)
                    {
                        resultsIndex = i;
                        break;
                    }
                    menuButtonList.ElementAt(i).Visibility = Visibility.Visible;
                    buttonCounter++;
                }

                if (buttonCounter < amountOfButtons)
                {
                    resultsIndex = menuButtonList.Count;
                }

                previousAmountOfButtons = buttonCounter;
            }
            else
            {

                resultsIndex = resultsIndex - previousAmountOfButtons;

                if (resultsIndex - (amountOfButtons + 1) <= 0)
                {
                    scrollUpButton.Visibility = Visibility.Collapsed;
                    amountOfButtons++;
                }
                
                for (int i = 0; i < amountOfButtons; i++)
                {
                    if (buttonCounter >= amountOfButtons)
                    {
                        break;
                    }

                    menuButtonList.ElementAt(i + (resultsIndex - amountOfButtons)).Visibility = Visibility.Visible;
                    buttonCounter++;
                }

                if (buttonCounter < amountOfButtons || resultsIndex < 0)
                {
                    resultsIndex = 0;
                }

                previousAmountOfButtons = buttonCounter;
            }

            return;
        }

        #endregion

        #region display map pins

        /** Shows markers for the preset content
         *  This include Buildings, Parking, and Food
         */
        private void showPresets(string id, string tags)
        {
            mapView.ExecuteJavascript("infowindow.close()");

            string jsFunc = "showPreset('" + id + "' , '" + tags + "')";

            Console.WriteLine("Zoom Start Slider: " + zoomSlider.Value);
            Console.WriteLine("Zoom Start Map: " + mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble());
            mapView.ExecuteJavascript(jsFunc);
            zoomSlider.Value = (mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble() - 12);
            Console.WriteLine("Zoom Finish: " + zoomSlider.Value);
            Console.WriteLine("Zoom Finsh Map: " + mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble());

        }

        /** Shows markers for group content
         *  This includes Bikes, Busses, ATMs, Restrooms
         */
        private void showGroupMarkers(string id, string type)
        {
            if (this.enabledPOIs.Contains(type))
            {
                removeGroupMarker(type);
                this.enabledPOIs.Remove(type);
                return;
            }

            string JSResult = mapView.ExecuteJavascriptWithResult("encodeURI(\"" + id + "\")").ToString();

            Console.WriteLine("JSResult: " + JSResult);

            string url = "http://maps.rit.edu/proxySearch/?q=*&wt=json&indent=off&start=0&rows=1000&fq=tag:" + JSResult +
                   "&fl=name,mdo_id,longitude,latitude";
            Console.WriteLine("URL: " + url);

            string functionCall = "placeGroupMarkers(" + "\"" + url + "\"" + "," + "\"" + type + "\"" + ");";
            this.enabledPOIs.Add(type);

            Console.WriteLine("Zoom Start Slider: " + zoomSlider.Value);
            Console.WriteLine("Zoom Start Map: " + mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble());
            mapView.ExecuteJavascript(functionCall);
            zoomSlider.Value = (mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble() - 12);
            Console.WriteLine("Zoom Finish: " + zoomSlider.Value);
            Console.WriteLine("Zoom Finsh Map: " + mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble());

        }

        private void removeGroupMarker(string id)
        {
            Console.WriteLine("Zoom Start Slider: " + (mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble() - 12));
            Console.WriteLine("Zoom Start Map: " + mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble());
            mapView.ExecuteJavascript("removeGroupMarkers('" + id + "')");
            zoomSlider.Value = (mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble() - 12);
            Console.WriteLine("Zoom Finsish: " + (mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble() - 12));
            Console.WriteLine("Zoom Finsh Map: " + mapView.ExecuteJavascriptWithResult("map.getZoom()").ToDouble());
        }

        #endregion

        #region build sub menus

        private List<HoverButton> buildResultMenu(String menu)
        {
            String tag = "";

            switch (menu)
            {
                case "foodResults":
                    tag = "Food";
                    break;
                case "academicBuildingsResults":
                    tag = "Academic+Building";
                    break;
                case "residentialBuildingsResults":
                    tag = "Residential+Building";
                    break;
                case "academicParkingResults":
                    tag = "Academic+Parking";
                    break;
                case "residentialParkingResults":
                    tag = "Residential+Parking";
                    break;
                case "visitorParkingResults":
                    tag = "Visitor+Parking";
                    break;
                default:
                    break;
            }

            List<MenuMapItem> items = getResultList(tag);
            List<HoverButton> hoverButtons = new List<HoverButton>();

            foreach (MenuMapItem item in items)
            {
                HoverButton button = new HoverButton();
                button.Click += new HoverButton.ClickHandler(item.button_Click);
                button.Text = item.name;
                button.Image = item.imageUrl;
                button.Height = 50;
                button.Width = 176;
                button.VerticalAlignment = VerticalAlignment.Top;
                button.HorizontalAlignment = HorizontalAlignment.Center;
                button.Padding = new Thickness(0);
                button.Margin = new Thickness(5);
                DockPanel.SetDock(button, Dock.Top);
                button.Visibility = Visibility.Collapsed;

                menuButtonPanel.Children.Add(button);

                hoverButtons.Add(button);
            }

            return hoverButtons;
        }

        private List<MenuMapItem> getResultList(String tag)
        {
            string locationURL = "http://maps.rit.edu/proxySearch/?q=*&wt=xml&indent=off&fq=tag:\"" + tag + "\"&rows=100&sort=name+asc";

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(locationURL);
            request.ContentType = "application/json; charset=utf-8";
            request.Accept = "application/xml, text/javascript, */*";
            request.Method = "GET";


            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();

            string xml = "";

            using (StreamReader reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    xml += reader.ReadLine();
                }
            }

            XmlDocument xmld = new XmlDocument();
            xmld.LoadXml(xml);

            XmlNodeList nodelist = xmld.GetElementsByTagName("doc");

            List<MenuMapItem> mapItems = new List<MenuMapItem>();


            Char let = 'A';
            /* bigger than 'Z' */
            if (tag.Contains("Parking")) { let = '['; }

            foreach (XmlNode xn in nodelist)
            {
                MenuMapItem mmi = new MenuMapItem();
                mmi.map = mapView;

                mmi.mapLetter = "" + let;

                foreach (XmlNode x in xn)
                {
                    switch (x.Attributes.GetNamedItem("name").Value)
                    {
                        case "name":
                            Console.WriteLine(x.InnerText);
                            mmi.name = x.InnerText;
                            break;

                        case "description":
                            Console.WriteLine(x.InnerText);
                            mmi.shortDesc = x.InnerText;
                            break;

                        case "mdo_id":
                            Console.WriteLine(x.InnerText);
                            mmi.mapId = x.InnerText;
                            break;
                    }
                }
                mapItems.Add(mmi);
                let++;
            }
            return mapItems;
        }

        #endregion

        #region menu nav
        private void scrollUpButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);
            showResultsMenu(true);
        }

        private void scrollDownButton_Click(object sender, EventArgs e)
        {
            collapseMenu(currentMenu);
            showResultsMenu();
        }

        #endregion
    }

}
